#include <stdlib.h>

#include "lib.h"

#include "slotguts.h"
#include "ffguts.h"
#include "slotspin.h"
#include "getrand.h"
#include "sltsql.h"
#include "slotconn.h"
#include "opts.h"
#include "log.h"


static int32 g_BigBonusPayouts[] =
{
	//The 128 big bonus payouts, form the big bonus sheet in the worksheet
	22,
	14,
	11,
	10,
	9,
	9,
	8,
	8,
	8,
	8,
	8,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2
};


static int32 g_SmallBonusPayouts[] = 
{
	//The 128 small bonus payouts, from the small bonus sheet in the worksheet
	9,
	7,
	7,
	6,
	6,
	6,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	5,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
};

enum WheelContents {
    BLANK,
    BURGER,
    TOMATO,
    PIE,
    PIZZA,
    PASTA,
    PUDDING,
	ICSCOOP,
	ICCONE,
	ICTOP,
	FFCHERRY,
	FFPIE,
	FFTIN
};


enum SpinResult
{
	//The order here looks odd, 
	//but it matches the paytable,
	//and is ordered by payout size
	EVT_LOSER = 0,
	EVT_ICECREAM,
	EVT_FOODFIGHT,
	EVT_2PIZZA,
	EVT_3BURGER,
	EVT_3TOMATO,
	EVT_2PASTA,
	EVT_3PIE,
	EVT_2PUDDING,
	EVT_3PIZZA,
	EVT_4BURGER,
	EVT_3PASTA,
	EVT_4TOMATO,
	EVT_4PIE,
	EVT_5BURGER,
	EVT_3PUDDING,
	EVT_4PIZZA,
	EVT_5TOMATO,
	EVT_5PIE,
	EVT_5PIZZA,
	EVT_4PASTA,
	EVT_4PUDDING,
	EVT_5PASTA,
	EVT_5PUDDING,
	NUMEVENTS
};

SlotSpin *
FoodFightSlotGuts::makeJackpot()
{
    uint8 *stops = new uint8[getReelCount()];
    SlotSpin *spin = new SlotSpin();

    spin->setBet(0);
    spin->setBonusGameType(0);


    /**
     * Hard set the reels to jackpots.  The assumption is
     * that the jackpot icon is the second to last icon on
     * the strip (the last being a blank).
     */
    for (uint8 i = 0; i < getReelCount(); i++)
    {
        stops[i] = getIcon(i, getIconCount(i) - 2)->position;
    }

    spin->setStops(getReelCount(), stops);

    classifyResult(spin);

    m_spins.push_back(spin);

    delete [] stops;

    return spin;
}




bool8 
FoodFightSlotGuts::isValidGuts()
{
    return (getGutsId() >= 16000 && getGutsId() < 16100);
}

int32
FoodFightSlotGuts::getMaxAggregate()
{
    return 56250;
}


uint8
FoodFightSlotGuts::classifyStops(uint8* stops,uint8 bet, uint8 line)
{
	uint8 result = EVT_LOSER;


	uint8 whichIcon = BLANK;
	uint8 testIcon = BLANK;
	bool8 streak = true; //Every line has a streak of at least one

	//Check the first icon (the rest have to match it)
	whichIcon = getIcon(0, stops[0])->iconid;
	testIcon = whichIcon;

	//Now, go through the rest, until the streak is over
	for ( uint8 i = 1; (i < getReelCount())&&(streak); i++ )
    {
		testIcon = getIcon(i, stops[i])->iconid;
		if(testIcon != whichIcon)
		{
			streak = false;
		}
	}
	
	//i is now the number of icons in a row (+1 if streak is false),
	//so pay it out
	if(!streak)
	{
		i-=1;
	}
	switch(i)
	{
		case 2:
			switch(whichIcon)
			{
				case BURGER:
					break;
				case TOMATO:
					break;
				case PIE:
					break;
				case PIZZA:
					result = EVT_2PIZZA;
					break;
				case PASTA:
					result = EVT_2PASTA;
					break;
				case PUDDING:
					result = EVT_2PUDDING;
					break;
			}
			break;		
		case 3:
			switch(whichIcon)
			{
				case BURGER:
					result = EVT_3BURGER;
					break;
				case TOMATO:
					result = EVT_3TOMATO;
					break;
				case PIE:
					result = EVT_3PIE;
					break;
				case PIZZA:
					result = EVT_3PIZZA;
					break;
				case PASTA:
					result = EVT_3PASTA;
					break;
				case PUDDING:
					result = EVT_3PUDDING;
					break;
			}
			break;
		case 4:
			switch(whichIcon)
			{
				case BURGER:
					result = EVT_4BURGER;
					break;
				case TOMATO:
					result = EVT_4TOMATO;
					break;
				case PIE:
					result = EVT_4PIE;
					break;
				case PIZZA:
					result = EVT_4PIZZA;
					break;
				case PASTA:
					result = EVT_4PASTA;
					break;
				case PUDDING:
					result = EVT_4PUDDING;
					break;
			}
			break;
		case 5:
			switch(whichIcon)
			{
				case BURGER:
					result = EVT_5BURGER;
					break;
				case TOMATO:
					result = EVT_5TOMATO;
					break;
				case PIE:
					result = EVT_5PIE;
					break;
				case PIZZA:
					result = EVT_5PIZZA;
					break;
				case PASTA:
					result = EVT_5PASTA;
					break;
				case PUDDING:
					result = EVT_5PUDDING;
					break;
			}
			break;
	}

	if (result != EVT_LOSER)
	{
		i=2;
	}

	return result;
}

void
FoodFightSlotGuts::classifyScatters(SlotSpin *spin)
{

	//Manually traverse through the 15 positions, looking for foodfight or ice cream icons.
	//Three of either is a winner
	uint8 numFoodFightIcons = 0;
	uint8 numIceCreamIcons = 0;
	uint8 iceCreamY[3];
	uint8 stop = 0;
	uint8 whichItem = BLANK;
	int32 payout = 0;

	for(int reel = 0; reel<5; reel++)
	{
		for(int row = 0; row < 3; row++)
		{
			stop = relativeWheelPosition(reel, spin->getStops()[reel], row);
			whichItem = getIcon(reel, stop)->iconid;

			//Ice Cream
			if(whichItem >= ICSCOOP && whichItem <= ICTOP)
			{
				iceCreamY[numIceCreamIcons] = row; //We send the client where the pieces are
				numIceCreamIcons++;
			}
			//Food Fight
			else if (whichItem >= FFCHERRY && whichItem <= FFTIN)
			{
				numFoodFightIcons++;
			}
		} //row
	} //reel

//BEGIN FUDGE
/*
	//FUDGE IT FOR NOW
	numIceCreamIcons = 0;
	iceCreamY[0] = 0;
	iceCreamY[1] = 1;
	iceCreamY[2] = 2;
	numFoodFightIcons = 3;
*/
//END FUDGE

	//Set the winners
	if(numIceCreamIcons >= 3)
	{
		//If it's icecream, go ahead and play it (we don't need no stinkin' bonus game)
		m_subGame->update(SGIDX_BONUSGAME,BGICECREAM);
		m_subGame->update(SGIDX_ICCONEY,iceCreamY[0]);
		m_subGame->update(SGIDX_ICSCOOPY,iceCreamY[1]);
		m_subGame->update(SGIDX_ICTOPY,iceCreamY[2]);
		payout = getRandomFromArray(g_SmallBonusPayouts, 128)*(spin->getTotalBet());
		m_subGame->update(SGIDX_ICVALUE,payout);
		readytofinish = false;

	}
	else if(numFoodFightIcons >=3)
	{
		//If it's food fight, just set up the targets, and give them the first one as a 'not-picked'
		totalBet = spin->getTotalBet(); //It'll get lost by the time the bonus game play comes back
		m_subGame->update(SGIDX_BONUSGAME,BGFOODFIGHT);
		initializeFoodFight();
		readytofinish = false;
	}
	else
	{
		m_subGame->update(SGIDX_BONUSGAME,BGNONE);
		readytofinish = true;
	}
}

void
FoodFightSlotGuts::initializeFoodFight()
{

	//Choose five targets, and give them the first one as not-picked
	int dumbnums[10] = {0,1,2,3,4,5,6,7,8,9};
	int chosennums[5];
	int totry=0;
	bool gotone = false;

	for(int i=0;i<5;i++)
	{
		while(!gotone)
		{
			//This rand is very slightly weighted (because of end effect)
			//It's okay here, because it doesn't affect payout at all
			//(Just target placement)
			totry = getrand() % 10;
			if(dumbnums[totry] >= 0)
				gotone = true;
		}
		chosennums[i] = dumbnums[totry];
		dumbnums[totry] = -1;
		gotone = false;
	}

	//This looks silly, but it avoids the problem of changing sgid order around later:
	m_subGame->update(SGIDX_FFTARGETONE,chosennums[0]);
	m_subGame->update(SGIDX_FFTARGETTWO,chosennums[1]);
	m_subGame->update(SGIDX_FFTARGETTHREE,chosennums[2]);
	m_subGame->update(SGIDX_FFTARGETFOUR,chosennums[3]);
	m_subGame->update(SGIDX_FFTARGETFIVE,chosennums[4]);

	//Set the first one as 'not picked yet'
	m_subGame->update(SGIDX_FFPICKONE,SGNOTPICKED);
	m_subGame->update(SGIDX_FFPICKTWO,SGNOTPICKED);
	m_subGame->update(SGIDX_FFPICKTHREE,SGNOTPICKED);
	m_subGame->update(SGIDX_FFPICKFOUR,SGNOTPICKED);
	m_subGame->update(SGIDX_FFPICKFIVE,SGNOTPICKED);

	//Set the values as losers
	m_subGame->update(SGIDX_FFVALUEONE,0);
	m_subGame->update(SGIDX_FFVALUETWO,0);
	m_subGame->update(SGIDX_FFVALUETHREE,0);
	m_subGame->update(SGIDX_FFVALUEFOUR,0);
	m_subGame->update(SGIDX_FFVALUEFIVE,0);


	//Figure out how many they'll successfully pick

	//There are five targets, and they'll always get 1 for free (and the last one is a guaranteed loser)
	//That means, that we just need to pick a random number between 1 and 4:
	m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
	m_subGame->update(SGIDX_NUMGOODPICKS,(getrand() % 4) + 1);
	m_subGame->update(SGIDX_ISDONE, 0);
 
	//We need to put in the spacers
	m_subGame->update(SGIDX_ICCONEY,0);
	m_subGame->update(SGIDX_ICSCOOPY,0);
	m_subGame->update(SGIDX_ICTOPY,0);
	m_subGame->update(SGIDX_ICVALUE,0);


}

void 
FoodFightSlotGuts::playBonusGame(uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData)
{
	bool8 problem = false;

	if(m_subGame->getData(SGIDX_BONUSGAME)!=FoodFightSlotGuts::BGFOODFIGHT)
	{
		//Trying to play when you're not in a bonus game!
		problem = true;
		Log::msgWarning("Foood Fight - Trying to play bonus game when not in a bonus game: %d", currentGameNum);
	}

	if(bonusGameType!=FoodFightSlotGuts::BGFOODFIGHT)
	{
		//We should only get here with pie picks	
		problem = true;
		Log::msgWarning("Foood Fight - Trying to play with bad bonus game type: %d", currentGameNum);
	}

	if(bonusDataCount!=1 || (bonusData[0]+5)/5 != 1)
	{
		//We should only have one pick, and it should be between 0 and 4	
		//We should only get here with pie picks	
		problem = true;
		Log::msgWarning("Foood Fight - Trying to play with funky pick (%d): %d", bonusData[0], currentGameNum);
	}

	if(!problem)
	{
		if((this->getSlotSpin(this->getSlotSpinCount()-1)) != (SlotSpin *) 0)
		{
			currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
			totalBet =(this->getSlotSpin(this->getSlotSpinCount()-1))->getTotalBet();


			int32 whichPick = -1;
			int32 whichPie = bonusData[0];

			//Figure out the payout first, then put it in the right place
			int32 pickValue = getRandomFromArray(g_BigBonusPayouts, 128)*(totalBet);


			//Figure out which (sequential) pick this is (first, second, etc.)
			//We don't use loops, so that we can change the order whenever we'd like
			if(m_subGame->getData(SGIDX_FFPICKONE)==SGNOTPICKED)
			{
				whichPick = 1;
			}
			else if(m_subGame->getData(SGIDX_FFPICKTWO)==SGNOTPICKED)
			{
				whichPick = 2;
			}
			else if(m_subGame->getData(SGIDX_FFPICKTHREE)==SGNOTPICKED)
			{
				whichPick = 3;
			}
			else if(m_subGame->getData(SGIDX_FFPICKFOUR)==SGNOTPICKED)
			{
				whichPick = 4;
			}
			else if(m_subGame->getData(SGIDX_FFPICKFIVE)==SGNOTPICKED)
			{
				whichPick = 5;
			}


			if(whichPick < 0)
			{
				//We've picked way too many
				problem = true;
				Log::msgWarning("Foood Fight - Too many picks (whichpick = %d): %d", whichPick, currentGameNum);
			}


			//If they've picked their limit, then they lose
			if(whichPick > m_subGame->getData(SGIDX_NUMGOODPICKS))
			{
				pickValue = 0; //Loser
				m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
				m_subGame->update(SGIDX_NUMGOODPICKS,0);
				m_subGame->update(SGIDX_ISDONE,1);
				readytofinish = true;
			}
			else
			{
				readytofinish = false;
			}

			//Write out the winner
			switch(whichPick)
			{
				case 1:
					m_subGame->update(SGIDX_FFPICKONE,whichPie);
					m_subGame->update(SGIDX_FFVALUEONE,pickValue);
					break;
				case 2:
					m_subGame->update(SGIDX_FFPICKTWO,whichPie);
					m_subGame->update(SGIDX_FFVALUETWO,pickValue);
					break;
				case 3:
					m_subGame->update(SGIDX_FFPICKTHREE,whichPie);
					m_subGame->update(SGIDX_FFVALUETHREE,pickValue);
					break;
				case 4:
					m_subGame->update(SGIDX_FFPICKFOUR,whichPie);
					m_subGame->update(SGIDX_FFVALUEFOUR,pickValue);
					break;
				case 5:
					pickValue = 0; //The last one is a guaranteed loser
					m_subGame->update(SGIDX_FFPICKFIVE,whichPie);
					m_subGame->update(SGIDX_FFVALUEFIVE,pickValue); //The last one is a guaranteed loser
					break;

			}
    
			//Write to the database
			createBonusGame(currentGameNum,10,whichPick,BGFOODFIGHT,whichPie,pickValue*(m_info->creditValue));
			//If we're done, finish the game
			if(isGameComplete())
			{
				completeGame();
			}
		}
		else
		{

			Log::msgWarning("Foood Fight - Can't load spin data: %d", currentGameNum);
		}
	}
}

bool8	
FoodFightSlotGuts::saveGame()
{
	//Base class
	bool8 result = SlotGuts::saveGame();

	if(result && !readytofinish)
	{
		//get the gamenum
		currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
		
		//And write what you can
		//In the icecream case, we can finish things off
		if(m_subGame->getData(SGIDX_BONUSGAME) == BGICECREAM)
		{
			//Ice Cream
			if(createBonusGame(currentGameNum,10,0,BGICECREAM,0,(m_subGame->getData(SGIDX_ICVALUE)*(m_info->creditValue))))
			{
				readytofinish = true;
			}
			else
			{
				result = false;
			}
		}
		else
		{
			//Food Fight
			if(!createBonusGame(currentGameNum,10,0,BGFOODFIGHT,m_subGame->getData(SGIDX_NUMGOODPICKS),0))
			{
				result = false;
			}

		}

	}

	return result;
}

bool8 
FoodFightSlotGuts::isGameComplete()
{
    return readytofinish;
}



#ifdef DEBUGSPIN
void FoodFightSlotGuts::Debug_SetLoserStops( uint8* pStops )
{
	pStops[0] = 16;
	pStops[1] = 17;
	pStops[2] = 18;
	pStops[3] = 29;
	pStops[4] = 18;
}
#endif